package cn.sherer.utils;

import java.util.List;
import java.util.Random;
import java.util.Base64;
import java.util.Arrays;
import java.util.ArrayList;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.awt.FontMetrics;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.security.SecureRandom;
import java.security.MessageDigest;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.digest.DigestUtils;

/**
 * 字符串工具类
 */
public class StringUtils {

    // <editor-fold defaultstate="collapsed" desc="判断数字">
    /**
     * 判断字符串是否为数字
     * @param str 字符串
     * @return 是否为数字
     */
    public static boolean isNumeric(String str) {
        return str != null && !str.trim().equalsIgnoreCase("") && str.trim().matches("-?[0-9]+.?[0-9]*");
    }

    /**
     * 判断字符串是否为整数
     * @param str 字符串
     * @return 是否为整数
     */
    public static boolean isInteger(String str) {
        return str != null && !str.trim().equalsIgnoreCase("") && str.trim().matches("^[-]?[\\d]*$");
    }

    /**
     * 判断字符串是否为整数
     * @param num 数字
     * @return 是否为整数
     */
    public static boolean isInteger(float num) {
        return Math.round(num) == num;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="判断空内容">
    /**
     * 内容为空时返回默认内容
     * @param source 内容
     * @param target 目标内容
     * @return 最终内容
     */
    public static String isNull(String source, String target) {
        return source != null ? source : target;
    }

    /**
     * 内容为空时返回默认内容
     * @param source 内容
     * @param target 目标内容
     * @return 最终内容
     */
    public static Object isNull(Object source, Object target) {
        return source != null ? source : target;
    }

    /**
     * 内容为空时返回默认内容
     * @param <T> 数据类型
     * @param source 内容
     * @param target 目标内容
     * @return 最终内容
     */
    public static <T> T ifNull(T source, T target) {
        return source != null ? source : target;
    }

    /**
     * 内容为空时返回默认内容
     * @param source 内容
     * @param isNull 空内容
     * @param notNull 非空内容
     * @return 最终内容
     */
    public static String isNull(String source, String isNull, String notNull) {
        return source != null ? notNull : isNull;
    }

    /**
     * 内容为空时返回默认内容
     * @param source 内容
     * @param isNull 空内容
     * @param notNull 非空内容
     * @return 最终内容
     */
    public static Object isNull(Object source, Object isNull, Object notNull) {
        return source != null ? notNull : isNull;
    }

    /**
     * 内容为空时返回默认内容
     * @param <T> 数据类型
     * @param source 内容
     * @param isNull 空内容
     * @param notNull 非空内容
     * @return 最终内容
     */
    public static <T> T ifNull(Object source, T isNull, T notNull) {
        return source != null ? notNull : isNull;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="转换数字">
    /**
     * 转换为Long类型
     * @param object 要转换的对象
     * @return 转换后的Long类型
     */
    public static long toLong(Object object) {
        return object == null ? 0 : (isNumeric(String.valueOf(object).trim()) ? Long.valueOf(String.valueOf(object).trim()) : 0);
    }

    /**
     * 转换为int类型
     * @param bool 要转换的bool类型
     * @return 转换后的int类型
     */
    public static int toInt(boolean bool) {
        return bool ? 1 : 0;
    }

    /**
     * 转换为int类型
     * @param object 要转换的对象
     * @return 转换后的int类型
     */
    public static int toInt(Object object) {
        return object == null ? 0 : (isNumeric(String.valueOf(object).trim()) ? Integer.valueOf(String.valueOf(object).trim()) : 0);
    }

    /**
     * 转换为float类型
     * @param object 要转换的对象
     * @return 转换后的float类型
     */
    public static float toFloat(Object object) {
        return object == null ? 0 : (isNumeric(String.valueOf(object).trim()) ? Float.valueOf(String.valueOf(object).trim()) : 0);
    }

    /**
     * 转换为double类型
     * @param object 要转换的对象
     * @return 转换后的double类型
     */
    public static double toDouble(Object object) {
        return object == null ? 0 : (isNumeric(String.valueOf(object).trim()) ? Double.valueOf(String.valueOf(object).trim()) : 0);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="换行字符串">
    private static final String linebreak = "\n"; // or "\r\n";

    /**
     * 按指定长度换行
     * @param string 要换行的字符串
     * @param lineLength 每行的长度
     * @return 换行后的字符串
     */
    public static String wrap(String string, int lineLength) {
        StringBuilder b = new StringBuilder();
        for (String line : string.split(Pattern.quote(linebreak))) {
            b.append(wrapLine(line, lineLength));
        }
        return b.toString();
    }

    /**
     * 按指定长度换行
     * @param string 要换行的字符串
     * @param lineLength 每行的长度
     * @return 换行后的字符串
     */
    private static String wrapLine(String line, int lineLength) {
        if (line.length() == 0) { return linebreak; }
        if (line.length() <= lineLength) { return line + linebreak; }
        String[] words = line.split(" ");
        StringBuilder allLines = new StringBuilder();
        StringBuilder trimmedLine = new StringBuilder();
        for (String word : words) {
            if (trimmedLine.length() + 1 + word.length() <= lineLength) {
                trimmedLine.append(word).append(" ");
            } else {
                allLines.append(trimmedLine).append(linebreak);
                trimmedLine = new StringBuilder();
                trimmedLine.append(word).append(" ");
            }
        }
        if (trimmedLine.length() > 0) { allLines.append(trimmedLine); }
        allLines.append(linebreak);
        return allLines.toString();
    }

    /**
     * 按指定长度换行
     * @param text 要换行的字符串
     * @param metrics 字体度量
     * @param maxWidth 最大宽度
     * @return 换行后的字符串
     */
    public static String[] wrap(String text, FontMetrics metrics, int maxWidth) {
        boolean isNewLine = true;
        List<String> list = new ArrayList<>();
        for (String line : text.split(Pattern.quote("\n"))) {
            int lineWidth = metrics.stringWidth(line);
            if (lineWidth <= maxWidth) {
                list.add(line.trim());
                isNewLine = true;
            } else {
                for (String word : line.split(" ")) {
                    String last = (list.isEmpty() ? "" : list.get(list.size() - 1));
                    lineWidth = metrics.stringWidth(last + word);
                    if (isNewLine) {
                        list.add(word + " ");
                    } else {
                        if (lineWidth <= maxWidth) {
                            list.set(list.size() - 1, last + word + " ");
                        } else {
                            list.set(list.size() - 1, last.trim());
                            list.add(word + " ");
                        }
                    }
                    isNewLine = false;
                }
            }
        }

        list.set(list.size() - 1, (list.isEmpty() ? "" : list.get(list.size() - 1)).trim());
        return list.toArray(new String[0]);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="逻辑运算">
    /**
     * 判断字符串是否不包含指定的字符串
     * @param source 要判断的字符串
     * @param cses 要判断的指定字符串
     * @return 是否不包含
     */
    public static boolean notContains(String source, CharSequence... cses) {
        for (CharSequence cse : cses) {
            if (!source.contains(cse)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断字符串是否包含指定的字符串
     * @param source 要判断的字符串
     * @param cses 要判断的指定字符串
     * @return 是否包含
     */
    public static boolean Contains(String source, CharSequence... cses) {
        for (CharSequence cse : cses) {
            if (source.contains(cse)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断字符串是否不以指定的字符串结尾
     * @param source 要判断的字符串
     * @param strings 要判断的指定字符串
     * @return 是否不以指定的字符串结尾
     */
    public static boolean endsWith(String source, String... strings) {
        for (String s : strings) {
            if (source.endsWith(s)) {
                return true;
            }
        }

        return false;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="加密和验证">
    /**
     * MD5加密
     * @param text 明文
     * @return 密文
     */
    public static String md5(String text) {
        return md5(text, "");
    }

    /**
     * MD5加密
     * @param text 明文
     * @param key 密钥
     * @return 密文
     */
    public static String md5(String text, String key) {
        return DigestUtils.md5Hex(text + key);
    }

    /**
     * MD5密文验证
     * @param text 明文
     * @param md5 密文
     * @return 是否验证通过
     */
    public static boolean verify(String text, String md5) {
        return md5(text).equalsIgnoreCase(md5);
    }

    /**
     * MD5密文验证
     * @param text 明文
     * @param key 密钥
     * @param md5 密文
     * @return 是否验证通过
     */
    public static boolean verify(String text, String key, String md5) {
        return md5(text, key).equalsIgnoreCase(md5);
    }


    /**
     * sha1加密 （不排序，UTF-8）
     * @param texts 明文数组
     * @return 密文
     * @throws NoSuchAlgorithmException 算法异常
     * @throws UnsupportedEncodingException 编码异常
     */
    public static String sha1(String... texts) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        return sha1(false, texts);
    }

    /**
     * sha1加密
     * @param sort 是否排序
     * @param texts 明文数组
     * @return 密文
     * @throws NoSuchAlgorithmException 算法异常
     * @throws UnsupportedEncodingException 编码异常
     */
    public static String sha1(Boolean sort, String... texts) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        if (sort) { Arrays.sort(texts); }
        StringBuilder content = new StringBuilder();
        for (String s : texts) { content.append(s); }
        return sha1(content.toString());
    }

    /**
     * sha1加密（UTF-8）
     * @param text 明文
     * @return 密文
     * @throws NoSuchAlgorithmException 算法异常
     * @throws UnsupportedEncodingException 编码异常
     */
    public static String sha1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        return sha1(text, "UTF-8");
    }

    /**
     * sha1加密
     * @param text 明文
     * @param encoding 编码
     * @return 密文
     * @throws NoSuchAlgorithmException 算法异常
     * @throws UnsupportedEncodingException 编码异常
     */
    public static String sha1(String text, String encoding) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        if (text == null || text.equals("")) return "";
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        MessageDigest digest = MessageDigest.getInstance("SHA1");
        digest.update(text.getBytes(encoding));
        byte[] md = digest.digest();
        int j = md.length;
        char[] buf = new char[j * 2];
        int k = 0;
        for (int i = 0; i < j; i++) {
            byte byte0 = md[i];
            buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
            buf[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(buf);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="获取指定长度的字符串内容">
    /**
     * 按字节获取指定长度的字符串内容
     * @param content 内容
     * @param length 长度
     * @return 指定长度的字符串内容
     * @throws UnsupportedEncodingException 异常
     */
    public static String getBytesContent(String content, int length) throws UnsupportedEncodingException {
        return getBytesContent(content, "UTF-8", length);
    }

    /**
     * 按字节获取指定长度的字符串内容
     * @param content 内容
     * @param encoding 编码
     * @param length 长度
     * @return 指定长度的字符串内容
     * @throws UnsupportedEncodingException 异常
     */
    public static String getBytesContent(String content, String encoding, int length) throws UnsupportedEncodingException {
        for (int i = content.length(); i >= 0; i--) {
            content = content.substring(0, i);
            if (content.getBytes(encoding).length <= length) {
                break;
            }
        }

        return content;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="判断语言">
    /**
     * 判断语言
     * @param str 要判断的文本内容
     * @return 语言：ug/cn/en
     */
    public static String getLanguage(String str) {
        String regExEN = "[\\w]+";
        String regExCN = "[\\u4e00-\\u9fa5]|[\\ufe30-\\uffa0]+";
        String regExUG = "[\\u0626-\\u06d5]+";

        if (Pattern.compile(regExCN).matcher(str).find()) {
            return "cn";
        }
        if (Pattern.compile(regExUG).matcher(str).find()) {
            return "ug";
        }
        if (Pattern.compile(regExEN).matcher(str).find()) {
            return "en";
        }

        return "";
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="编码与解码">
    /**
     * 获取Base64编码
     * @param str 要编码的的文本内容
     * @return 编码内容
     * @throws java.io.UnsupportedEncodingException 异常
     */
    public static String getBase64Encode(String str) throws UnsupportedEncodingException {
        return Base64.getEncoder().encodeToString(str.getBytes("UTF-8"));
    }

    /**
     * 获取Base64解码
     * @param str 要解码的的文本内容
     * @return 解码内容
     * @throws java.io.UnsupportedEncodingException 异常
     */
    public static String getBase64Decode(String str) throws UnsupportedEncodingException {
        return new String(Base64.getDecoder().decode(str), "UTF-8");
    }

    /**
     * 获取URL编码
     * @param url 要编码的URL地址
     * @return 编码内容
     * @throws java.io.UnsupportedEncodingException 异常
     */
    public static String getUrlEncode(String url) throws UnsupportedEncodingException {
        return URLEncoder.encode(url, "UTF-8");
    }

    /**
     * 获取URL解码
     * @param url 要解码的URL地址
     * @return 解码内容
     * @throws java.io.UnsupportedEncodingException 异常
     */
    public static String getUrlDecode(String url) throws UnsupportedEncodingException {
        return URLDecoder.decode(url, "UTF-8");
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="处理表情">
    /**
     * 替换表情
     * @param content 内容
     * @param replacement 替换内容
     * @return 替换后的内容
     */
    public static String replaceAllEmoji(String content, String replacement) {
        content = isNull(content, "");
        replacement = isNull(replacement, "");
        content = content.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", replacement);
        Pattern pattern = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]");
        Matcher matcher = pattern.matcher(content);
        return matcher.replaceAll(replacement);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="分割">
    /**
     * 去除前后指定字符
     * @param source 目标字符串
     * @param beTrim 要删除的指定字符
     * @return 删除之后的字符串 调用示例：System.out.println(trim(", ashuh ",","));
     */
    public static String trim(String source, String beTrim) {
        if (source == null) { return ""; }
        source = source.trim();
        if (source.isEmpty()) { return ""; }
        if (beTrim == null || beTrim.isEmpty()) { return source; }

        beTrim = beTrim.toLowerCase();
        String beginChar = source.substring(0, 1).toLowerCase();
        while (!source.isEmpty() && beginChar.equals(beTrim)) {
            source = source.substring(1);
            if (!source.isEmpty()) {
                beginChar = source.substring(0, 1).toLowerCase();
            }
        }

        if (source.isEmpty()) { return ""; }

        String endChar = source.substring(source.length() - 1).toLowerCase();
        while (!source.isEmpty() && endChar.equals(beTrim)) {
            source = source.substring(0, source.length() - 1);
            if (!source.isEmpty()) {
                endChar = source.substring(source.length() - 1).toLowerCase();
            }
        }

        return source;
    }

    /**
     * 分割字符串
     * @param content 内容
     * @param spliter 分隔符
     * @return 分割后的字符串列表
     */
    public static List<String> split(String content, String spliter) {
        List<String> list = new ArrayList<>();
        try {
            for (String string : trim(isNull(content, ""), spliter).split(spliter)) {
                if (!isNull(string, "").equals("")) {
                    list.add(string);
                }
            }
        } catch (Exception e) {}
        return list;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="其他">

    /**
     * 获取随机字符串（16）
     * @return 随机字符串
     */
    public static String getNonceStr() {
        return getNonceStr(16);
    }

    /**
     * 获取随机字符串
     * @param length 长度
     * @return 随机字符串
     */
    public static String getNonceStr(int length) {
        char[] nonceChars = new char[length];
        Random RANDOM = new SecureRandom();
        String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    // </editor-fold>
}
